IMPLEMENTATION MODULE Tad_Inscripciones;

FROM libc IMPORT exit, printf;
FROM MathLib0 IMPORT sqrt;
FROM FpuIO IMPORT WriteReal;
FROM StrIO IMPORT WriteString, WriteLn;
FROM Scan IMPORT OpenSource;
FROM NumberIO IMPORT ReadInt,WriteInt;
FROM FIO IMPORT OpenToRead,File,EOF,WriteLine,ReadString,Close;
FROM Storage IMPORT ALLOCATE, DEALLOCATE;
FROM DynamicStrings IMPORT String, Slice, CopyOut, Index, InitString;
FROM StringConvert IMPORT StringToInteger, IntegerToString;
FROM SFIO IMPORT WriteS,OpenToWrite;
FROM Tad_CargaDatos IMPORT Carga_Lineas,CargaLinea;
FROM Tad_ControlEstudio IMPORT Creditos;
IMPORT Tad_Lista;
IMPORT Tad_Estudiante;
IMPORT Tad_Materia;
IMPORT Tad_Profesor;
IMPORT Tad_Nota;
IMPORT Tad_Par;
IMPORT Tad_Curso;
IMPORT Tad_Solicitud;
IMPORT Tad_ArbolBinomial;
IMPORT Tad_ReporteMateria;


PROCEDURE Carga_Cursos(data : File; l : Tad_Lista.Lista);
VAR i,n		:INTEGER;
	valido	: BOOLEAN;
BEGIN
	n := CargaLinea(data);
	FOR i := 0 TO n-1 DO        
		valido := Tad_Lista.Lista_Agregar(l,Tad_Curso.Carga(data));
		
		IF NOT valido THEN
			WriteLn();
			WriteString('El proceso de la carga de los archivos no se logro correctamente');
			WriteLn();
		END;
	END;
END Carga_Cursos;


PROCEDURE Carga_Solicitudes(data : File; x: Tad_Lista.Lista (*Notas*); 
							y: Tad_Lista.Lista (*Estudiantes*); 
							z: Tad_Lista.Lista (*Materias*)) : Tad_ArbolBinomial.Arbol;
VAR pares	        : Tad_Lista.Lista;
	i,n 	        : INTEGER;
	valido,entra 	: BOOLEAN;
	arb 	        : Tad_ArbolBinomial.Arbol;
	j 		: CARDINAL;
	peticion        : Tad_Solicitud.Solicitud;
	indice 	        : REAL;
	par     	: Tad_Par.Par;
BEGIN
	arb := Tad_ArbolBinomial.CrearArbol();
	pares := Tad_Lista.Crear_Lista(Tad_Par.Imprimir);
	pares := Lista_Indices(x,y,z);
	n := CargaLinea(data);
        entra := FALSE;
	FOR i := 0 TO n-1 DO        
		peticion := Tad_Solicitud.Carga(data);
		
		FOR j := 0 TO Tad_Lista.Lista_Tamanio(pares)-1 DO
			par := Tad_Lista.Lista_Obtener(pares,j);
			IF Tad_Solicitud.GetCodigoEstudiante(peticion) = Tad_Par.GetX(par) THEN
				indice := Tad_Par.GetY(par);
                                entra := TRUE;
			END; 
		END;
		IF entra THEN
		        Tad_ArbolBinomial.Agregar(arb,peticion,indice);
		END;
                entra := FALSE;
	END;
	RETURN arb;
END Carga_Solicitudes;

PROCEDURE Lista_Indices(x: Tad_Lista.Lista; y: Tad_Lista.Lista; z: Tad_Lista.Lista) : Tad_Lista.Lista;
VAR indice		: REAL;
	creditos,suma,suma_creditos,k, codigoEstudiante: INTEGER;
	i,j			: CARDINAL;
	tamx, tamy	: CARDINAL ;
	nota 		: Tad_Nota.Nota;
	estudiante 	: Tad_Estudiante.Estudiante;
	listaPares 	: Tad_Lista.Lista;
	agregada 	: BOOLEAN;
BEGIN
	listaPares := Tad_Lista.Crear_Lista(Tad_Par.Imprimir);
	i := 0;
	tamy := Tad_Lista.Lista_Tamanio(y);
	tamx :=  Tad_Lista.Lista_Tamanio(x);
	(*Recorriendo estudiantes*)
	WHILE i < tamy DO
		suma := 0;
		suma_creditos := 0;
		indice := 0.0;
		j :=0;
		(*Recorriendo notas del estudiante*)
		WHILE j < tamx DO		
			nota := Tad_Lista.Lista_Obtener(x,j);
			estudiante := Tad_Lista.Lista_Obtener(y,i);
			IF  (Tad_Estudiante.GetCodigo(estudiante) = 
				Tad_Nota.GetCodigoEstudiante(nota)) THEN
				creditos := Creditos(z,Tad_Nota.GetCodigoMateria(nota));
				suma := suma + Tad_Nota.GetNota(nota)*creditos;
				suma_creditos := suma_creditos + creditos;
			END;
			j := j + 1;
		END;
		estudiante := Tad_Lista.Lista_Obtener(y,i);
		codigoEstudiante := Tad_Estudiante.GetCodigo(estudiante);
		IF suma_creditos > 0 THEN
			indice := FLOAT(suma)/FLOAT(suma_creditos);
			agregada := Tad_Lista.Lista_Agregar(listaPares,Tad_Par.Par_Crear(codigoEstudiante,indice));
		END;
		IF suma_creditos = 0 THEN
			agregada := Tad_Lista.Lista_Agregar(listaPares,Tad_Par.Par_Crear(codigoEstudiante,0.0));
		END;
		i:= i+1;
	END;
	RETURN listaPares;
END Lista_Indices;
  
 
PROCEDURE Asignacion_Cursos_Obligatorios (codigo_curso : INTEGER; materias : Tad_Lista.Lista; estudiantes : Tad_Lista.Lista; cursos : Tad_Lista.Lista; solicitudes : Tad_ArbolBinomial.Arbol) : Tad_Lista.Lista;
VAR i,j,k : CARDINAL;
VAR cupos : INTEGER;
VAR nombre : String;
VAR materia : Tad_Materia.Materia;
VAR solicitud : Tad_Solicitud.Solicitud;
VAR solicitudes_desatendidas : Tad_Lista.Lista;
VAR solicitudes_ordenadas,estudiantes_ordenados : Tad_Lista.Lista;
VAR valido, salida : BOOLEAN;
VAR estudiantes_arbol : Tad_ArbolBinomial.Arbol;
VAR estudiante: Tad_Estudiante.Estudiante;
VAR string : ARRAY [0..19] OF CHAR;
VAR curso: Tad_Curso.Curso;
VAR solicitudesArb : Tad_ArbolBinomial.Arbol;

BEGIN
	k := 0;
	
	FOR i := 0 TO Tad_Lista.Lista_Tamanio(materias) - 1 DO
		materia := Tad_Lista.Lista_Obtener(materias,i);
		IF codigo_curso = Tad_Materia.GetCodigo(materia) THEN
			nombre := Tad_Materia.GetNombre(materia);
		END;
	END;
	
	solicitudes_desatendidas := Tad_Lista.Crear_Lista(Tad_Solicitud.Imprimir);
        solicitudesArb := Tad_ArbolBinomial.Clonar(solicitudes);
	solicitudes_ordenadas := Tad_ArbolBinomial.ListaOrdenada(solicitudesArb,Tad_Solicitud.Imprimir);
	i := 0;
        j := 0;
	WHILE (i < Tad_Lista.Lista_Tamanio(cursos)) DO
		curso := Tad_Lista.Lista_Obtener(cursos,i);
		IF Tad_Curso.GetCodigoMateria(curso) = codigo_curso THEN
			IF Tad_Curso.GetTipo(curso) = 'o' THEN
                                estudiantes_arbol := Tad_ArbolBinomial.CrearArbol();
				cupos := Tad_Curso.GetCupo(curso);
				WriteLn();
				WriteInt(codigo_curso,0);
				WriteString(' ');
				CopyOut(string,nombre);
				WriteString(string);
				WriteString(' ');
				WriteInt(Tad_Curso.GetSeccion(curso),0);
				WriteLn();
	
				
				salida := TRUE;
                                j := 0;
				WHILE (j < Tad_Lista.Lista_Tamanio(solicitudes_ordenadas)) AND salida DO
					solicitud := Tad_Lista.Lista_Obtener(solicitudes_ordenadas,j);
		
					IF Tad_Solicitud.GetCodigoMateria(solicitud) = codigo_curso THEN
						IF cupos > 0 THEN
							FOR k := 0 TO Tad_Lista.Lista_Tamanio(estudiantes)-1 DO
								estudiante := Tad_Lista.Lista_Obtener(estudiantes,k);
								IF (Tad_Solicitud.GetCodigoEstudiante(solicitud) = Tad_Estudiante.GetCodigo(estudiante)) AND valido THEN
									Tad_ArbolBinomial.Agregar(estudiantes_arbol,estudiante,FLOAT(Tad_Estudiante.GetCodigo(estudiante)));
									
								END;
							END;
                                                        
						        cupos := cupos - 1;
                                                       
							valido := Tad_Lista.Lista_Eliminar(solicitudes_ordenadas,j);
								IF NOT valido THEN
									WriteLn();
									WriteString('la solicitud se elimino de la lista de solicitudes ordenadas de forma incorrecta');
									WriteLn();
								END;
								j := j - 1;
						ELSE						
							salida := FALSE;
						END;
					ELSE
						valido := Tad_Lista.Lista_Eliminar(solicitudes_ordenadas,j);
								IF NOT valido THEN
									WriteLn();
									WriteString('la solicitud se elimino de la lista de solicitudes ordenadas de forma incorrecta');
									WriteLn();
								END;
						j := j - 1;
					END;
					j := j + 1;								
				END;
				(*Impresion de alumnos en el curso*)
				estudiantes_ordenados := Tad_ArbolBinomial.ListaOrdenada(estudiantes_arbol,Tad_Estudiante.Imprimir);
                                Tad_Lista.Lista_Imprimir(estudiantes_ordenados);
				WriteLn();
			END;
		END;
                i:= i + 1;
	END;
	j := 0;
	WHILE j < Tad_Lista.Lista_Tamanio(solicitudes_ordenadas) DO
		solicitud := Tad_Lista.Lista_Obtener(solicitudes_ordenadas,j);
			IF Tad_Solicitud.GetCodigoMateria(solicitud) = codigo_curso THEN
				valido := Tad_Lista.Lista_Agregar(solicitudes_desatendidas,solicitud);
				IF NOT valido THEN
					WriteLn();
					WriteString('la solicitud se agrego a la lista de solicitudes desatendidas de forma incorrecta');
					WriteLn();
				END;
			END;
		j := j + 1;
	END;
	RETURN solicitudes_desatendidas;

END Asignacion_Cursos_Obligatorios; 


PROCEDURE Reporte_Cursos_Obligatorios (estudiantes : Tad_Lista.Lista; cursos : Tad_Lista.Lista; solicitudes : Tad_ArbolBinomial.Arbol; materias:Tad_Lista.Lista);
VAR     i,j,k 						: CARDINAL;
	cupos, codigo_curso,seccion                     : INTEGER;
	curso 						: Tad_Curso.Curso;
	solicitud 					: Tad_Solicitud.Solicitud;
	solicitudes_ordenadas            		: Tad_Lista.Lista;
	valido 						: BOOLEAN;
	estudiante					: Tad_Estudiante.Estudiante;
 	archivo						: File;
 	controlS					: String;
        solicitudesArb                                  : Tad_ArbolBinomial.Arbol;
BEGIN
	archivo := OpenToWrite(InitString("ReporteCursosObligatorios.txt"));
	i := 0;
        solicitudesArb := Tad_ArbolBinomial.Clonar(solicitudes);
	solicitudes_ordenadas := Tad_ArbolBinomial.ListaOrdenada(solicitudesArb,Tad_Solicitud.Imprimir);
	(*Itero sobre los cursos*)
	WHILE (i < Tad_Lista.Lista_Tamanio(cursos)) DO
		curso := Tad_Lista.Lista_Obtener(cursos,i);
		codigo_curso := Tad_Curso.GetCodigoMateria(curso);
		IF Tad_Curso.GetTipo(curso) = 'o' THEN		
			cupos := Tad_Curso.GetCupo(curso);
			(*Copiar curso en el archivo*)
			controlS := WriteS(archivo,Tad_Curso.CursoToString(curso,materias));
			WriteLine(archivo);
			valido := TRUE;
			(*Busco en la lista de solicitudes, las asociadas al curso*)
                        j := 0;
			WHILE j < Tad_Lista.Lista_Tamanio(solicitudes_ordenadas) DO
				solicitud := Tad_Lista.Lista_Obtener(solicitudes_ordenadas,j);	
				(*Si la solicitud es sobre este curso*)		
				IF Tad_Solicitud.GetCodigoMateria(solicitud) = codigo_curso THEN
					(*Si aun quedan cupos disponibles en el curso*)
					IF cupos > 0 THEN
						(*Busco el estudiante asociado a la solicitud en la lista de estudiantes*)
                                                k := 0;
						WHILE k < Tad_Lista.Lista_Tamanio(estudiantes)-1 DO
							estudiante := Tad_Lista.Lista_Obtener(estudiantes,k);
							(*Si encuentro al estudiante*)
							IF (Tad_Solicitud.GetCodigoEstudiante(solicitud) = Tad_Estudiante.GetCodigo(estudiante)) THEN
								(*Escribo al estudiante en el archivo y resto un cupo al curso*)
								controlS := WriteS(archivo,Tad_Estudiante.EstudianteToString(estudiante));
								WriteLine(archivo);
								cupos := cupos - 1;
								k := Tad_Lista.Lista_Tamanio(estudiantes);
							END;(*ENDIF*)
                                                k := k + 1;
						END;(*ENDFOR*)
						(*Elimino la solicitud de la solicitud ya revisada*)
						valido := Tad_Lista.Lista_Eliminar(solicitudes_ordenadas,j);
						j:=j-1;
					END;(*ENDIF*)
				END;(*ENDIF*)
                                j := j + 1;
			END;(*ENDFOR*)
		END;(*ENDIF*)
		i := i + 1;
	END;(*ENDWHILE*)
        Close(archivo);
END Reporte_Cursos_Obligatorios;

PROCEDURE Solicitudes_NoAtendidas (estudiantes : Tad_Lista.Lista; solicitudes : Tad_ArbolBinomial.Arbol; cursos : Tad_Lista.Lista);
VAR i,j,k : CARDINAL;
VAR cupos, codigo_curso : INTEGER;
VAR curso : Tad_Curso.Curso;
VAR solicitud,solicitud2 : Tad_Solicitud.Solicitud;
VAR solicitudes_ordenadas : Tad_Lista.Lista;
VAR valido, salida : BOOLEAN;
VAR estudiantes_arbol : Tad_ArbolBinomial.Arbol;
VAR estudiantes_lista : Tad_Lista.Lista;
VAR estudiante,estudiante2: Tad_Estudiante.Estudiante;
VAR archivo : File;
VAR control,estudianteString : String;
VAR string : ARRAY[0..19] OF CHAR;
VAR solicitudesArb : Tad_ArbolBinomial.Arbol;
BEGIN
    solicitudesArb := Tad_ArbolBinomial.Clonar(solicitudes);
	solicitudes_ordenadas := Tad_ArbolBinomial.ListaOrdenada(solicitudesArb,Tad_Solicitud.Imprimir); 
	estudiantes_arbol := Tad_ArbolBinomial.CrearArbol();
	i := 0;
	WHILE (i < Tad_Lista.Lista_Tamanio(cursos)) DO
		curso := Tad_Lista.Lista_Obtener(cursos,i);
		cupos := Tad_Curso.GetCupo(curso);
        codigo_curso := Tad_Curso.GetCodigoMateria(curso);
		valido := TRUE;
		salida := TRUE;
                j:= 0;
		WHILE (j < Tad_Lista.Lista_Tamanio(solicitudes_ordenadas)) AND salida DO
			solicitud := Tad_Lista.Lista_Obtener(solicitudes_ordenadas,j);

			IF Tad_Solicitud.GetCodigoMateria(solicitud) = codigo_curso THEN
				IF cupos > 0 THEN
					cupos := cupos - 1;
					valido := Tad_Lista.Lista_Eliminar(solicitudes_ordenadas,j);
					IF NOT valido THEN
						WriteLn();
						WriteString('la solicitud se elimino de la lista de solicitudes ordenadas de forma incorrecta');
						WriteLn();
					END;
					j := j - 1;
				ELSE
					salida := FALSE;
				END;
			END;
			j := j + 1;								
		END;
       	
        i := i + 1;
	END;

	j := 0;
	WHILE j < Tad_Lista.Lista_Tamanio(solicitudes_ordenadas) DO
   	solicitud := Tad_Lista.Lista_Obtener(solicitudes_ordenadas,j);
	 (*	solicitud2 := Tad_Lista.Lista_Obtener(solicitudes_ordenadas,j+1);
		WHILE (Tad_Solicitud.GetCodigoEstudiante(solicitud) = Tad_Solicitud.GetCodigoEstudiante(solicitud2)) DO              
				valido := Tad_Lista.Lista_Eliminar(solicitudes_ordenadas,j+1);
				solicitud2 := Tad_Lista.Lista_Obtener(solicitudes_ordenadas,j+1);
		IF NOT valido THEN
			WriteLn();
			WriteString('la solicitud se elimino de la lista de solicitudes ordenadas de forma incorrecta');
						END;
		END;*)
		salida := TRUE;
		i := 0;
		WHILE (i < Tad_Lista.Lista_Tamanio(estudiantes)) AND salida DO
			estudiante := Tad_Lista.Lista_Obtener(estudiantes,i);
			IF (Tad_Solicitud.GetCodigoEstudiante(solicitud) = Tad_Estudiante.GetCodigo(estudiante)) AND salida THEN
				Tad_ArbolBinomial.Agregar(estudiantes_arbol,estudiante,FLOAT(Tad_Estudiante.GetCodigo(estudiante)));
				salida := FALSE;       
			END;
                i := i + 1;
		END;
		j := j + 1;
	END;
	estudiantes_lista := Tad_ArbolBinomial.ListaOrdenada(estudiantes_arbol,Tad_Estudiante.Imprimir);

	j :=0;
	WHILE j < Tad_Lista.Lista_Tamanio(estudiantes_lista)-1 DO
   	estudiante := Tad_Lista.Lista_Obtener(estudiantes_lista,j);
	estudiante2 := Tad_Lista.Lista_Obtener(estudiantes_lista,j+1);
		WHILE (Tad_Estudiante.GetCodigo(estudiante) = Tad_Estudiante.GetCodigo(estudiante2)) 
			AND  (j < Tad_Lista.Lista_Tamanio(estudiantes_lista)-1) DO              
				valido := Tad_Lista.Lista_Eliminar(estudiantes_lista,j+1);
				estudiante2 := Tad_Lista.Lista_Obtener(estudiantes_lista,j+1);
				IF NOT valido THEN
					WriteLn();
					WriteString('la solicitud se elimino de la lista de solicitudes ordenadas de forma incorrecta');
				END;
		END;
		j := j+1;
	END;
	Tad_Lista.Lista_Imprimir(estudiantes_lista);
	i := Tad_Lista.Lista_Tamanio(estudiantes_lista)-1;
	archivo := OpenToWrite(InitString("estudiantesNoAsignados.txt"));
	WHILE i >= 0 DO
		estudiante := Tad_Lista.Lista_Obtener(estudiantes_lista,i);
		estudianteString := Tad_Estudiante.EstudianteToString(estudiante);
		control := WriteS(archivo,estudianteString);
		WriteLine(archivo);
        i := i-1;
	END;
	
	(*Cierro el archivo*)
	Close(archivo);
	
END Solicitudes_NoAtendidas;

PROCEDURE Reporte_Materias(materias : Tad_Lista.Lista; solicitudesX : Tad_ArbolBinomial.Arbol; cursos : Tad_Lista.Lista);
VAR reportes	        		: Tad_ArbolBinomial.Arbol;
	materia				: Tad_Materia.Materia;
	curso				: Tad_Curso.Curso;
	solicitud			: Tad_Solicitud.Solicitud;
	i,j				: CARDINAL;
	cod_materia			: INTEGER;
	cupos, solicitados              : INTEGER;
	valido				: BOOLEAN;
	reporte 			: Tad_ReporteMateria.Reporte;
	solicitudes			: Tad_Lista.Lista;
	reportes_ord		        : Tad_Lista.Lista;
        solicitudesArb                  : Tad_ArbolBinomial.Arbol;
        listaSolicitAux	        	: Tad_Lista.Lista;
	archivo                         : File;
	control,estudianteString        : String;
	ss : ARRAY [0..100] OF CHAR;
BEGIN
	listaSolicitAux := Tad_Lista.Crear_Lista(Tad_Solicitud.Imprimir);
	(*Creo un arbol de reportes*)
	reportes := Tad_ArbolBinomial.CrearArbol();
	(*Guardo el arbol de solicitudes en una lista*)
	
    solicitudesArb := Tad_ArbolBinomial.Clonar(solicitudesX);
	solicitudes := Tad_ArbolBinomial.ListaOrdenada(solicitudesArb,Tad_Solicitud.Imprimir);
	i := 0;
	(*Agrego la informacion de las materias (codigo como clave) al arbol de reportes*)
	WHILE(i < Tad_Lista.Lista_Tamanio(materias))DO
		materia := Tad_Lista.Lista_Obtener(materias,i);
		cod_materia := Tad_Materia.GetCodigo(materia);
		(*Tad_ArbolBinomial.Agregar(reportes,NIL,FLOAT(cod_materia));*)
		j := 0;
		cupos := 0;
		solicitados := 0;
		(*Busco en cursos la cantidad de cupos disponible para la materia*)
		WHILE(j < Tad_Lista.Lista_Tamanio(cursos))DO
			curso := Tad_Lista.Lista_Obtener(cursos,j);
			IF(Tad_Curso.GetCodigoMateria(curso)=cod_materia)THEN
				cupos := cupos + Tad_Curso.GetCupo(curso);
			END;
			j := j + 1;
		END;
		j := 0;
		(*Busco en solicitudes la cantidad de cupos solicitados*)
		WHILE(j < Tad_Lista.Lista_Tamanio(solicitudes))DO
			solicitud := Tad_Lista.Lista_Obtener(solicitudes,j);
			IF(Tad_Solicitud.GetCodigoMateria(solicitud)=cod_materia)THEN
				solicitados := solicitados + 1;
			END;
			j := j + 1;
		END;
		IF(solicitados > cupos) THEN 
			(*Creo el elemento a ingresar al arbol*)
			reporte := Tad_ReporteMateria.Reporte_Crear(cod_materia,cupos,solicitados);	
			Tad_ArbolBinomial.Agregar(reportes,reporte,FLOAT(cod_materia));
		END;
		i := i + 1;
	END;
	
	reportes_ord := Tad_ArbolBinomial.ListaOrdenada(reportes,Tad_ReporteMateria.Imprimir);
	
	(*Copio en el archivo la lista de materias con solicitudes - cupo > 0*)
    i := Tad_Lista.Lista_Tamanio(reportes_ord);
    archivo := OpenToWrite(InitString("ReporteMaterias.txt"));
    
	WHILE i > 0  DO
               reporte := Tad_Lista.Lista_Obtener(reportes_ord,i-1);
                WriteLine(archivo);
               (*Reporte to string resta solicitudes con cupos y devuelve CodMateria  #SolNoAtendidas*)
               control := WriteS(archivo,Tad_ReporteMateria.ReporteToString(reporte));
               WriteLine(archivo);
               i := i-1;
       END;

	(*Cierro el archivo*)
	Close(archivo);
	

END Reporte_Materias;

END Tad_Inscripciones.
